/**
 * @UiControl.cpp
 * Copyright 2013 (C) FatalEror / Dean Bahari
 * 
 * UiPack is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * See LICENSE file in main folder for more information.
 */

#include "UiCommon.hpp"
#include "UiApp.hpp"
#include "UiBase.hpp"
#include "UiControl.hpp"
#include "UiEvent.hpp"
#include "UiTooltip.hpp"

UiControl::UiControl()
{
	mTooltip = NULL;
	mState   = 0;

	UiEvent evCreate;
	this->onCreate(evCreate);
}

UiControl::~UiControl()
{
	if (mTooltip)
		delete mTooltip;
}

int UiControl::getState()
{
	return mState;
}

void UiControl::setState(int state)
{
	mState = state;
}

void UiControl::showTooltip(const wchar_t *text)
{
	mTooltip = new UiTooltip(this, text);
}

void UiControl::onCreate(UiEvent &ev)
{
}

void UiControl::onPaint(UiEvent &ev)
{
}

void UiControl::onResize(UiEvent &ev)
{
}

void UiControl::onMove(UiEvent &ev)
{
}

void UiControl::onClick(UiEvent &ev)
{
}

void UiControl::onHover(UiEvent &ev)
{
}

void UiControl::onEnter(UiEvent &ev)
{
}

void UiControl::onLeave(UiEvent &ev)
{
}

LRESULT CALLBACK UiControl::handleCustomProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) {
	case WM_DESTROY:
		if (mTooltip)
			mTooltip->close();
		break;
	case WM_NCHITTEST:
		return HTCLIENT;
	case WM_ERASEBKGND:
		return 1;
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hDC = BeginPaint(this->getHandle(), &ps);
		HDC hDCBuffer = UiApp::getCurrentApp()->getDCBuffer();

		UiEvent evPaint(hDCBuffer);
		this->onPaint(evPaint);
		
		BitBlt(hDC, 0, 0, this->getWidth(), this->getHeight(), hDCBuffer, 0, 0, SRCCOPY);
		EndPaint(this->getHandle(), &ps);
	} break;
	case WM_SIZE:
	{
		mWidth = LOWORD(lParam);
		mHeight = HIWORD(lParam);

		UiEvent evResize(mWidth, mHeight);
		this->onResize(evResize);
	} break;
	case WM_MOUSEMOVE:
	{
		UiEvent evHover(LOWORD(lParam), HIWORD(lParam));
		this->onHover(evHover);

		if (!(this->getState() & UiControl::UI_HOVERED)) {
			this->mState |= UiControl::UI_HOVERED;
			UiEvent evEnter;
			this->onEnter(evEnter);

			if (mTooltip)
				mTooltip->show();

			TRACKMOUSEEVENT tme;
			tme.cbSize      = sizeof(tme);
			tme.dwFlags     = TME_LEAVE;
			tme.dwHoverTime = HOVER_DEFAULT;
			tme.hwndTrack   = this->getHandle();
			TrackMouseEvent(&tme);
		}
	} break;
	case WM_MOUSELEAVE:
	{
		this->mState &= ~UiControl::UI_HOVERED;
		UiEvent evLeave;
		this->onLeave(evLeave);

		if (mTooltip)
			mTooltip->hide();
	} break;
	case WM_LBUTTONDOWN:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_LEFT | UiEvent::UI_MOUSE_CLICK);
		this->onClick(evClick);

		SetCapture(this->getHandle());
		this->mState |= UiControl::UI_SELECTED;
	} break;
	case WM_LBUTTONDBLCLK:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_LEFT | UiEvent::UI_MOUSE_DCLICK);
		this->onClick(evClick);
	} break;
	case WM_LBUTTONUP:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_LEFT | UiEvent::UI_MOUSE_RELEASE);
		this->onClick(evClick);

		ReleaseCapture();
		this->mState &= ~UiControl::UI_SELECTED;
	} break;
	case WM_RBUTTONDOWN:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_RIGHT | UiEvent::UI_MOUSE_CLICK);
		this->onClick(evClick);

		SetCapture(this->getHandle());
	} break;
	case WM_RBUTTONDBLCLK:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_RIGHT | UiEvent::UI_MOUSE_DCLICK);
		this->onClick(evClick);
	} break;
	case WM_RBUTTONUP:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_RIGHT | UiEvent::UI_MOUSE_RELEASE);
		this->onClick(evClick);

		ReleaseCapture();
	} break;
	case WM_MBUTTONDOWN:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_MIDDLE | UiEvent::UI_MOUSE_CLICK);
		this->onClick(evClick);

		SetCapture(this->getHandle());
	} break;
	case WM_MBUTTONDBLCLK:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_MIDDLE | UiEvent::UI_MOUSE_DCLICK);
		this->onClick(evClick);
	} break;
	case WM_MBUTTONUP:
	{
		UiEvent evClick(UiEvent::UI_MOUSE_MIDDLE | UiEvent::UI_MOUSE_RELEASE);
		this->onClick(evClick);

		ReleaseCapture();
	} break;
	default:
		return DefWindowProc(this->getHandle(), msg, wParam, lParam);
	}

	return 0;
}